package com.ym.controller.admin;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.ym.common.constant.Constants;
import com.ym.core.domain.APIResponse;
import com.ym.core.domain.BaseController;
import com.ym.medical.enums.FileTypeEnum;
import com.ym.medical.service.IFileInforSV;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpAiOpenService;
import me.chanjar.weixin.mp.api.WxMpMaterialService;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ws.schild.jave.AudioAttributes;
import ws.schild.jave.Encoder;
import ws.schild.jave.EncodingAttributes;
import ws.schild.jave.MultimediaObject;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.util.Map;

/**
 * 微信公众号相关
 *
 * @author: 李涛
 * @version: 2019年11月21日 9:35
 */
@RestController
@RequestMapping(value = "/admin/wechat/mp", headers = Constants.Api.VERSION)
@Validated
@Slf4j
public class WxMpController extends BaseController {

	@Autowired
	private WxMpService wxMpService;

	@Autowired
	private IFileInforSV fileInforSV;


	/**
	 * 跳转到获取code页面
	 *
	 * @param redirectUrl 跳转地址
	 * @param response
	 * @throws Exception
	 */
	@GetMapping("/oauth/code")
	public void authorize(String redirectUrl, String scope, String state, HttpServletResponse response) throws Exception {
		//1.取出code，做登录操作，看是否已经登录
		String redirectUri = wxMpService.oauth2buildAuthorizationUrl(redirectUrl, scope, state);
		log.info("redirectUri地址={}", redirectUri);
		response.sendRedirect(redirectUri);
	}

	/**
	 * 获取js安全相关配置
	 *
	 * @param url 地址
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/create/signature")
	public APIResponse<WxJsapiSignature> createSignature(String url) throws Exception {
		WxJsapiSignature jsapiSignature = wxMpService.createJsapiSignature(url);
		log.info("微信签名数据:{}", JSONObject.toJSONString(jsapiSignature));
		return successData(jsapiSignature);
	}

	/**
	 * 获得jsapi_ticket,不强制刷新jsapi_ticket
	 *
	 * @param
	 * @return
	 */
	@GetMapping("/jsapi/ticket")
	public APIResponse<String> jsapiTicket() {
		WxMpAiOpenService aiOpenService = wxMpService.getAiOpenService();
		String jsapiTicket = null;
		Map<String, String> paramMap = Maps.newHashMap();
		try {
			jsapiTicket = this.wxMpService.getJsapiTicket();
			paramMap.put(jsapiTicket, jsapiTicket);
		} catch (WxErrorException e) {
			log.error("获取[jsapi_ticket失败]: {}", e.getMessage());
		}
		return successData(jsapiTicket);

	}


	/**
	 * 验证请求来自微信
	 *
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @param echostr
	 * @return
	 */
	@GetMapping(value = "/portal/auth", produces = MediaType.TEXT_PLAIN_VALUE)
	public String portalAuth(
			@RequestParam(name = "signature", required = false) String signature,
			@RequestParam(name = "timestamp", required = false) String timestamp,
			@RequestParam(name = "nonce", required = false) String nonce,
			@RequestParam(name = "echostr", required = false) String echostr
	) {

		log.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature,
				timestamp, nonce, echostr);
		if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
			throw new IllegalArgumentException("请求参数非法，请核实!");
		}

		if (wxMpService.checkSignature(timestamp, nonce, signature)) {
			return echostr;
		}
		return "非法请求";
	}

	/**
	 * 处理微信发来的用户消息
	 *
	 * @param requestBody
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @param openid
	 * @param encType
	 * @param msgSignature
	 * @return
	 */
	@PostMapping(value = "/portal/auth", produces = MediaType.APPLICATION_XML_VALUE)
	public String post(
			@RequestBody String requestBody,
			@RequestParam("signature") String signature,
			@RequestParam("timestamp") String timestamp,
			@RequestParam("nonce") String nonce,
			@RequestParam("openid") String openid,
			@RequestParam(name = "encrypt_type", required = false) String encType,
			@RequestParam(name = "msg_signature", required = false) String msgSignature
	) {
		log.info("\n接收微信请求：[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
						+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
				openid, signature, encType, msgSignature, timestamp, nonce, requestBody);

		if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
			throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
		}

		String out = null;
		if (encType == null) {
			// 明文传输的消息
			WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
			WxMpXmlOutMessage outMessage = this.route(inMessage);
			if (outMessage == null) {
				return "";
			}

			out = outMessage.toXml();
		} else if ("aes".equalsIgnoreCase(encType)) {
			// aes加密的消息
			WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(),
					timestamp, nonce, msgSignature);
			log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
			WxMpXmlOutMessage outMessage = this.route(inMessage);
			if (outMessage == null) {
				return "";
			}

			out = outMessage.toEncryptedXml(wxMpService.getWxMpConfigStorage());
		}

		log.debug("\n组装回复信息：{}", out);
		return out;
	}

	private WxMpXmlOutMessage route(WxMpXmlMessage message) {
		try {
			WxMpMessageRouter wxMpMessageRouter = new WxMpMessageRouter(wxMpService);
			return wxMpMessageRouter.route(message);
		} catch (Exception e) {
			log.error("路由消息时出现异常！", e);
		}
		return null;
	}

	/**
	 * <pre>
	 * 自定义菜单创建接口
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
	 * 如果要创建个性化菜单，请设置matchrule属性
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @return 如果是个性化菜单，则返回menuid，否则返回null
	 */
	@ApiOperation("自定义菜单创建接口")
	@PostMapping("/menu/create")
	public String menuCreate(@RequestBody WxMenu wxMenu) throws WxErrorException {
		return this.wxMpService.getMenuService().menuCreate(wxMenu);
	}

	/**
	 * <pre>
	 * 自定义菜单创建接口
	 * 详情请见： https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
	 * 如果要创建个性化菜单，请设置matchrule属性
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @return 如果是个性化菜单，则返回menuid，否则返回null
	 */
	@ApiOperation("自定义菜单创建接口")
	@PostMapping("/menu/create/byjson")
	public String menuCreate(@RequestBody String json) throws WxErrorException {
		return this.wxMpService.getMenuService().menuCreate(json);
	}

	/**
	 * <pre>
	 * 删除个性化菜单接口
	 * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @param menuId 个性化菜单的menuid
	 */
	@ApiOperation("删除个性化菜单接口")
	@GetMapping("/menu/delete/{menuId}")
	public void menuDelete(@PathVariable String menuId) throws WxErrorException {
		this.wxMpService.getMenuService().menuDelete(menuId);
	}

	/**
	 * <pre>
	 * 自定义菜单查询接口
	 * 详情请见： https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
	 * </pre>
	 */
	@ApiOperation("菜单查询接口")
	@GetMapping("/menu/get")
	public WxMpMenu menuGet() throws WxErrorException {
		return this.wxMpService.getMenuService().menuGet();
	}

	@ApiOperation("媒体文件下载(文件arm下载)")
	@GetMapping("/media/get")
	public void mediaGet(String mediaId, HttpServletResponse response) throws Exception {
		WxMpMaterialService materialService = wxMpService.getMaterialService();
		File file = materialService.mediaDownload(mediaId);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/octet-stream");
		response.setHeader("Content-disposition",
				"attachment; filename=" + file.getName());

		try (
				FileInputStream inputStream = new FileInputStream(file);
				ServletOutputStream outputStream = response.getOutputStream();
		) {
			IoUtil.copy(inputStream, outputStream);
			IoUtil.close(inputStream);
			IoUtil.close(outputStream);
		}
	}


	@ApiOperation("媒体文件下载(arm的base64)")
	@GetMapping("/media/get2")
	public String mediaGet2(String mediaId, HttpServletResponse response) throws Exception {
		WxMpMaterialService materialService = wxMpService.getMaterialService();
		File file = materialService.mediaDownload(mediaId);
		String encode = Base64.encode(file);
		return encode;
	}

	@ApiOperation("媒体文件下载(mp3的base64)")
	@GetMapping("/media/get3")
	public String mediaGet3(String mediaId, HttpServletResponse response) throws Exception {
		WxMpMaterialService materialService = wxMpService.getMaterialService();
		File file = materialService.mediaDownload(mediaId);
		File encode = armToMp3(file);
		String encodeStr = Base64.encode(encode);
		encode.deleteOnExit();
		return encodeStr;
	}

	@ApiOperation("媒体文件下载(文件MP3)")
	@GetMapping("/media/get4")
	public void mediaGet4(String mediaId, HttpServletResponse response) throws Exception {
		WxMpMaterialService materialService = wxMpService.getMaterialService();
		File file = materialService.mediaDownload(mediaId);
		File encode = armToMp3(file);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/octet-stream");
		response.setHeader("Content-disposition",
				"attachment; filename=" + encode.getName());

		try (
				FileInputStream inputStream = new FileInputStream(encode);
				ServletOutputStream outputStream = response.getOutputStream()
		) {
			IoUtil.copy(inputStream, outputStream);
		} finally {
			encode.deleteOnExit();
		}
	}


	@ApiOperation("微信语音聊天媒体文件上传至七牛云")
	@GetMapping("/media/voice/upload2qiniu")
	public APIResponse uploadRec2Qiniu(
			@RequestParam String mediaId
	) throws Exception {
		WxMpMaterialService materialService = wxMpService.getMaterialService();
		File file = materialService.mediaDownload(mediaId);
		File mp3File = armToMp3(file);
		String fileId = fileInforSV.uploadFile(mp3File, FileTypeEnum.REC, "chat_details", "attach", "语音上传", 1L);
		return successData(fileId);
	}

	/**
	 * arm文件变成MP3 的Base64
	 *
	 * @param source
	 * @return
	 */
	public static File armToMp3(File source) {
		File target = null;
		try {
			target = File.createTempFile(IdUtil.fastSimpleUUID(), ".mp3");
			AudioAttributes audio = new AudioAttributes();
			Encoder encoder = new Encoder();
			audio.setCodec("libmp3lame");
			EncodingAttributes attrs = new EncodingAttributes();
			attrs.setFormat("mp3");
			attrs.setAudioAttributes(audio);
			MultimediaObject multimediaObject = new MultimediaObject(source);
			encoder.encode(multimediaObject, target, attrs);
			return target;
		} catch (Exception e) {
			log.error("转换异常:{}", ExceptionUtil.getMessage(e));
		}
		return target;
	}

}
